import sys, os
from PySide6.QtCore import Qt
from PySide6.QtGui import QGuiApplication, QIcon
from PySide6.QtWidgets import QApplication, QMainWindow, QLabel, QPushButton, QTextEdit, QLineEdit, QFileDialog, QScrollArea, QRadioButton
from functools import partial
import pandas as pd
import yagmail, smtplib


class MyWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        # 单元格像素大小
        self.pixel_x = 80
        self.pixel_y = 40
        # 组件间距
        self.space_x = 5
        self.space_y = 5
        # 窗口大小
        self.window_width = 10 * self.pixel_x + self.space_x * 6
        self.window_height = 16 * self.pixel_y + self.space_y * 1
        # 组件长宽单位
        self.loc_x = self.pixel_x + self.space_x
        self.loc_y = self.pixel_y + self.space_y

        # 表格拆分字段
        self.text_zd = ''
        # 源文件目录
        self.source_path = ''
        # 源文件
        self.source_file = ''
        # 是否发送邮件
        self.flag_mail = False
        # 邮件相关配置
        self.mail_addr = ''
        self.mail_pwd = ''
        self.mail_host = 'smtp.jx.chinamobile.com'
        self.mail_title = ''
        self.mail_content = ''
        self.to_file = ''
        self.cc_file = ''
        self.common_file = ''
        self.attach_list = []

        self.copy = 'CopyRight 2024 zhyoung'

        # 获取屏幕分辨率
        self.screen = QGuiApplication.primaryScreen()
        self.screen_size = self.screen.availableGeometry()

        # 固定窗口大小
        self.setFixedSize(self.window_width, self.window_height)
        # 将窗口居中显示
        self.move((self.screen_size.width() - self.window_width) // 2, 
                  (self.screen_size.height() - self.window_height) // 2)

        # 程序标题
        self.setWindowIcon(QIcon('./icon.ico'))
        self.setWindowTitle('文件处理工具')

        # 版权声明
        self.copy_label = QLabel('CopyRight 2024 zhyoung@live.cn 相关附件模板，请关注公众号【周Young】，回复“邮件分发”获取', self)
        self.copy_label.setGeometry(1 * self.loc_x, 0, 8 * self.pixel_x + 6 * self.space_x, 1 * self.pixel_y)
        self.copy_label.setStyleSheet("QLabel {qproperty-alignment: AlignCenter; padding: 5px; color: #AAAAAA}")

        # 输入区-拆分字段提示
        self.label_zd = QLabel('输入拆分字段：', self)
        self.label_zd.setGeometry(1 * self.loc_x, 1 * self.loc_y, 
                                   2 * self.pixel_x, 1 * self.pixel_y)
        self.label_zd.setStyleSheet("QLabel {qproperty-alignment: AlignCenter; border: 1px solid gray; border-radius: 5px; padding: 5px}")
        # 输入区-拆分字段
        self.input_zd = QLineEdit(self)
        # 绑定TEXT改变事件
        self.input_zd.textChanged.connect(lambda text: self.input_change(text, "zd"))
        self.input_zd.setGeometry(3 * self.loc_x, 1 * self.loc_y, 
                                   2 * self.pixel_x, 1 * self.pixel_y)
        self.input_zd.setStyleSheet("QLineEdit {border: 1px solid gray; border-radius: 5px; padding: 5px}")
        self.input_zd.clearFocus()

        # 按钮-选择文件目录
        self.button_source_path = QPushButton('点击选择文件目录', self)
        self.button_source_path.setGeometry(1 * self.loc_x, 2 * self.loc_y, 
                                   2 * self.pixel_x, 1 * self.pixel_y)
        self.button_source_path.setStyleSheet("QPushButton {text-align: center; border: 1px solid gray; border-radius: 5px; padding: 5px}")
        self.button_source_path.clicked.connect(self.path_choose)
        self.label_source_path = QLabel(self)        
        # self.label_source_file.setStyleSheet("QLabel {border: 1px solid gray; border-radius: 5px; padding: 5px}")
        self.label_source_path.setGeometry(3 * self.loc_x, 2 * self.loc_y, 
                                   2 * self.pixel_x, 1 * self.pixel_y)
        # 设置横向滚动展示
        self.scroll_source_path = QScrollArea(self)
        self.scroll_source_path.setWidget(self.label_source_path)
        self.scroll_source_path.setGeometry(3 * self.loc_x, 2 * self.loc_y, 
                                   2 * self.pixel_x, 1 * self.pixel_y)
        self.scroll_source_path.setWidgetResizable(True)
        self.scroll_source_path.setStyleSheet("QScrollArea {border: 1px solid gray; border-radius: 5px; padding: 5px}")

        # 选择拆分文件
        self.button_source_file = QPushButton('点击选择拆分文件', self)
        self.button_source_file.setGeometry(1 * self.loc_x, 3 * self.loc_y, 
                                   2 * self.pixel_x, 1 * self.pixel_y)
        self.button_source_file.setStyleSheet("QPushButton {text-align: center; border: 1px solid gray; border-radius: 5px; padding: 5px}")
        self.button_source_file.clicked.connect(partial(self.file_choose, 'source_file'))
        self.label_source_file = QLabel(self)        
        # self.label_source_file.setStyleSheet("QLabel {border: 1px solid gray; border-radius: 5px; padding: 5px}")
        self.label_source_file.setGeometry(3 * self.loc_x, 3 * self.loc_y, 
                                   2 * self.pixel_x, 1 * self.pixel_y)
        # 设置横向滚动展示
        self.scroll_source_file = QScrollArea(self)
        self.scroll_source_file.setWidget(self.label_source_file)
        self.scroll_source_file.setGeometry(3 * self.loc_x, 3 * self.loc_y, 
                                   2 * self.pixel_x, 1 * self.pixel_y)
        self.scroll_source_file.setWidgetResizable(True)
        self.scroll_source_file.setStyleSheet("QScrollArea {border: 1px solid gray; border-radius: 5px; padding: 5px}")

        # 是否发送邮件
        self.label_mail_flag = QLabel('是否发送邮件：' + '否', self)
        self.label_mail_flag.setGeometry(1 * self.loc_x, 4 * self.loc_y, 
                                   2 * self.pixel_x, 1 * self.pixel_y)
        self.label_mail_flag.setStyleSheet("QLabel {qproperty-alignment: AlignCenter; border: 1px solid gray; border-radius: 5px; padding: 5px}")
        self.radio_mail_true = QRadioButton('是', self)
        self.radio_mail_true.setGeometry(3 * self.loc_x + self.space_x, 4 * self.loc_y, 
                                   1 * self.pixel_x, 1 * self.pixel_y)
        self.radio_mail_false = QRadioButton('否', self)
        self.radio_mail_false.setGeometry(4 * self.loc_x, 4 * self.loc_y, 
                                   1 * self.pixel_x, 1 * self.pixel_y)
        self.radio_mail_false.setChecked(True)
        self.radio_mail_true.clicked.connect(partial(self.mail_flag_change, True))
        self.radio_mail_false.clicked.connect(partial(self.mail_flag_change, False))

        # 开始拆分按钮
        self.button_start_split = QPushButton("点击开始拆分", self)
        self.button_start_split.setGeometry(1 * self.loc_x, 5 * self.loc_y, 
                                   4 * self.pixel_x + 2 * self.space_x, 1 * self.pixel_y)
        self.button_start_split.setStyleSheet("QPushButton {text-align: center; border: 1px solid red; border-radius: 5px; padding: 5px;}")
        self.button_start_split.clicked.connect(self.start_split)

        # 日志展示view
        self.log_text = QTextEdit(self)
        # 设置只读
        self.log_text.setReadOnly(True)
        self.log_text.setGeometry(5 * self.loc_x, 1 * self.loc_y, 
                                  4 * self.pixel_x, 5 * (self.pixel_y + self.space_y) - self.space_y)
        self.log_text.setStyleSheet("QTextEdit {border: 1px solid gray; border-radius: 5px; padding: 5px;}")
        
        # 输入区-邮件发送提示
        self.label_mail_tip = QLabel('如果需要发送邮件，则需补充下方信息', self)
        self.label_mail_tip.setGeometry(1 * self.loc_x, 6 * self.loc_y, 
                                   8 * self.pixel_x, 1 * self.pixel_y)
        self.label_mail_tip.setStyleSheet("QLabel {qproperty-alignment: AlignCenter; padding: 5px; color: #AAAAAA;}")

        # 输入区-发送邮箱
        self.input_mail_addr = QLineEdit(self)
        self.input_mail_addr.setPlaceholderText('输入发件人邮箱地址')
        # 绑定TEXT改变事件
        self.input_mail_addr.textChanged.connect(lambda text: self.input_change(text, "mail_addr"))
        self.input_mail_addr.setGeometry(1 * self.loc_x, 7 * self.loc_y, 
                                   4 * self.pixel_x + 2 * self.space_x, 1 * self.pixel_y)
        self.input_mail_addr.setStyleSheet("QLineEdit {border: 1px solid gray; border-radius: 5px; padding: 5px}")
        self.input_mail_addr.clearFocus()

        # 输入区-邮箱密码
        self.input_mail_pwd = QLineEdit(self)
        self.input_mail_pwd.setPlaceholderText('输入发件人邮箱密码')
        # 绑定TEXT改变事件
        self.input_mail_pwd.textChanged.connect(lambda text: self.input_change(text, "mail_pwd"))
        self.input_mail_pwd.setGeometry(5 * self.loc_x, 7 * self.loc_y, 
                                   4 * self.pixel_x + 2 * self.space_x, 1 * self.pixel_y)
        self.input_mail_pwd.setStyleSheet("QLineEdit {border: 1px solid gray; border-radius: 5px; padding: 5px}")
        self.input_mail_pwd.clearFocus()

        # 输入区-邮箱host
        self.input_mail_host = QLineEdit('smtp.jx.chinamobile.com', self)
        self.input_mail_host.setPlaceholderText('输入发件人邮箱host')
        # 绑定TEXT改变事件
        self.input_mail_host.textChanged.connect(lambda text: self.input_change(text, "mail_host"))
        self.input_mail_host.setGeometry(1 * self.loc_x, 8 * self.loc_y, 
                                   4 * self.pixel_x + 2 * self.space_x, 1 * self.pixel_y)
        self.input_mail_host.setStyleSheet("QLineEdit {border: 1px solid gray; border-radius: 5px; padding: 5px}")
        self.input_mail_host.clearFocus()

        # 选择收件人文件
        self.button_to_file = QPushButton('点击选择收件人文件', self)
        self.button_to_file.setGeometry(5 * self.loc_x, 8 * self.loc_y, 
                                   2 * self.pixel_x, 1 * self.pixel_y)
        self.button_to_file.setStyleSheet("QPushButton {text-align: center; border: 1px solid gray; border-radius: 5px; padding: 5px}")
        self.button_to_file.clicked.connect(partial(self.file_choose, 'to_file'))
        self.label_to_file = QLabel('必选', self)
        self.label_to_file.setStyleSheet("QLabel {color: gray;}")             
        self.label_to_file.setGeometry(7 * self.loc_x, 8 * self.loc_y, 
                                   2 * self.pixel_x, 1 * self.pixel_y)
        # 设置横向滚动展示
        self.scroll_to_file = QScrollArea(self)
        self.scroll_to_file.setWidget(self.label_to_file)
        self.scroll_to_file.setGeometry(7 * self.loc_x, 8 * self.loc_y, 
                                   2 * self.pixel_x, 1 * self.pixel_y)
        self.scroll_to_file.setWidgetResizable(True)
        self.scroll_to_file.setStyleSheet("QScrollArea {border: 1px solid gray; border-radius: 5px; padding: 5px}")

        # 选择抄送人文件
        self.button_cc_file = QPushButton('点击选择抄送人文件', self)
        self.button_cc_file.setGeometry(1 * self.loc_x, 9 * self.loc_y, 
                                   2 * self.pixel_x, 1 * self.pixel_y)
        self.button_cc_file.setStyleSheet("QPushButton {text-align: center; border: 1px solid gray; border-radius: 5px; padding: 5px}")
        self.button_cc_file.clicked.connect(partial(self.file_choose, 'cc_file'))
        self.label_cc_file = QLabel('可选', self)
        self.label_cc_file.setStyleSheet("QLabel {color: gray;}")         
        self.label_cc_file.setGeometry(3 * self.loc_x, 9 * self.loc_y, 
                                   2 * self.pixel_x, 1 * self.pixel_y)
        # 设置横向滚动展示
        self.scroll_cc_file = QScrollArea(self)
        self.scroll_cc_file.setWidget(self.label_cc_file)
        self.scroll_cc_file.setGeometry(3 * self.loc_x, 9 * self.loc_y, 
                                   2 * self.pixel_x, 1 * self.pixel_y)
        self.scroll_cc_file.setWidgetResizable(True)
        self.scroll_cc_file.setStyleSheet("QScrollArea {border: 1px solid gray; border-radius: 5px; padding: 5px}")

        # 选择共同抄送人文件
        self.button_common_file = QPushButton('点击选择共同抄送人文件', self)
        self.button_common_file.setGeometry(5 * self.loc_x, 9 * self.loc_y, 
                                   2 * self.pixel_x, 1 * self.pixel_y)
        self.button_common_file.setStyleSheet("QPushButton {text-align: center; border: 1px solid gray; border-radius: 5px; padding: 5px}")
        self.button_common_file.clicked.connect(partial(self.file_choose, 'common_file'))
        self.label_common_file = QLabel('必选，至少添加自己为共同抄送人', self)        
        self.label_common_file.setStyleSheet("QLabel {color: gray;}")   
        self.label_common_file.setGeometry(7 * self.loc_x, 9 * self.loc_y, 
                                   2 * self.pixel_x, 1 * self.pixel_y)
        # 设置横向滚动展示
        self.scroll_common_file = QScrollArea(self)
        self.scroll_common_file.setWidget(self.label_common_file)
        self.scroll_common_file.setGeometry(7 * self.loc_x, 9 * self.loc_y, 
                                   2 * self.pixel_x, 1 * self.pixel_y)
        self.scroll_common_file.setWidgetResizable(True)
        self.scroll_common_file.setStyleSheet("QScrollArea {border: 1px solid gray; border-radius: 5px; padding: 5px}")

        # 输入区-邮件标题
        self.input_title = QLineEdit(self)
        self.input_title.setPlaceholderText('输入邮件标题（必填）')
        # 绑定TEXT改变事件
        self.input_title.textChanged.connect(lambda text: self.input_change(text, "title"))
        self.input_title.setGeometry(1 * self.loc_x, 10 * self.loc_y, 
                                   8 * self.pixel_x + 6 * self.space_x, 1 * self.pixel_y)
        self.input_title.setStyleSheet("QLineEdit {border: 1px solid gray; border-radius: 5px; padding: 5px}")
        self.input_title.clearFocus()

        # 邮件正文
        self.content_text = QTextEdit(self)
        self.content_text.setPlaceholderText('输入邮件正文（选填）')
        # 设置只读
        self.content_text.setGeometry(1 * self.loc_x, 11 * self.loc_y, 
                                  8 * self.pixel_x + 6 * self.space_x, 2 * (self.pixel_y + self.space_y) - self.space_y)
        self.content_text.setStyleSheet("QTextEdit {border: 1px solid gray; border-radius: 5px; padding: 5px;}")
        self.content_text.textChanged.connect(self.content_change)

        # 选择邮件附件
        self.button_attach_file = QPushButton('点击选择客服文档或其他', self)
        self.button_attach_file.setGeometry(1 * self.loc_x, 13 * self.loc_y, 
                                   2 * self.pixel_x, 1 * self.pixel_y)
        self.button_attach_file.setStyleSheet("QPushButton {text-align: center; border: 1px solid gray; border-radius: 5px; padding: 5px}")
        self.button_attach_file.clicked.connect(partial(self.file_choose, 'attach_file'))
        self.label_attach_file = QLabel('可选项', self)
        self.label_attach_file.setStyleSheet("QLabel {color: gray;}")   
        self.label_attach_file.setGeometry(3 * self.loc_x, 13 * self.loc_y, 
                                   4 * self.pixel_x + 2 * self.space_x, 1 * self.pixel_y)
        # 设置横向滚动展示
        self.scroll_attach_file = QScrollArea(self)
        self.scroll_attach_file.setWidget(self.label_attach_file)
        self.scroll_attach_file.setGeometry(3 * self.loc_x, 13 * self.loc_y, 
                                   4 * self.pixel_x + 2 * self.space_x, 1 * self.pixel_y)
        self.scroll_attach_file.setWidgetResizable(True)
        self.scroll_attach_file.setStyleSheet("QScrollArea {border: 1px solid gray; border-radius: 5px; padding: 5px}")
        # 清空附件按钮
        self.button_clear = QPushButton('清空附件', self)
        self.button_clear.setGeometry(7 * self.loc_x, 13 * self.loc_y, 
                                   2 * self.pixel_x, 1 * self.pixel_y)
        self.button_clear.setStyleSheet("QPushButton {text-align: center; border: 1px solid gray; border-radius: 5px; padding: 5px}")
        self.button_clear.clicked.connect(self.attach_clear)


    # 日志记录函数-log_view
    def append_log(self, text):
        self.log_text.append(text)
        self.log_text.append('++++++++++++')

    # 输入区-拆分字段改变事件
    def input_change(self, text, flag):
        # print('flag: ', text, flag)
        if flag=='zd':
            self.text_zd = text
            self.label_zd.setText('拆分字段：' + self.text_zd)
        elif flag=='mail_addr':
            self.mail_addr = text
        elif flag=='mail_pwd':
            self.mail_pwd = text
        elif flag=='mail_host':
            self.mail_host = text
        elif flag=='title':
            self.mail_title = text
        else:
            pass


    # 选择文件
    def file_choose(self, flag_type):
        # print('file_choose: ', flag_type)
        file_dialog = QFileDialog()
        # file_path, _ = file_dialog.getOpenFileName(self, '选择文件', '', '*.xlsx')
        file_path, _ = file_dialog.getOpenFileName(self, '选择文件', '', 'All Files (*)')
        if file_path:
            if flag_type == 'source_file':
                self.source_file = file_path
                self.label_source_file.setText(file_path)
                self.append_log('---Tip选择拆分文件：' + file_path)
            elif flag_type == 'config_file':
                self.config_file = file_path
                self.label_config_file.setText(file_path)
                self.append_log('---Tip选择配置文件：' + file_path)
            elif flag_type == 'to_file':
                self.to_file = file_path
                self.label_to_file.setText(file_path)
                self.append_log('---Tip选择收件人文件：' + file_path)
            elif flag_type == 'cc_file':
                self.cc_file = file_path
                self.label_cc_file.setText(file_path)
                self.append_log('---Tip选择抄送人文件：' + file_path)
            elif flag_type == 'common_file':
                self.common_file = file_path
                self.label_common_file.setText(file_path)
                self.append_log('---Tip选择共同收件人文件：' + file_path)
            elif flag_type == 'attach_file':
                self.attach_list.append(file_path)
                self.label_attach_file.setText(str(self.attach_list))
                self.append_log('---Tip选择附件文件：' + str(self.attach_list))
            else:
                pass

    # 是否发送邮件
    def mail_flag_change(self, flag):
        self.flag_mail = flag
        self.label_mail_flag.setText('是否发送邮件：' + ('是' if self.flag_mail else '否'))

    # 选择目录
    def path_choose(self):
        # print('path_choose')
        path_dialog = QFileDialog()
        file_path = path_dialog.getExistingDirectory(self, '选择文件夹', '')
        if file_path:
            self.label_source_path.setText(file_path)
            self.source_path = file_path
            self.append_log('---Tip选择源目录：' + file_path)

    # 清空附件
    def attach_clear(self):
        self.attach_list = []

    # 开始拆分
    def start_split(self):
        # print('start_split')
        self.log_text.clear()
        try:
            os.makedirs(os.path.join(self.source_path, 'split_res'))
        except Exception as e:
            # print('---创建文件夹失败：', e)
            self.append_log('---Error创建文件夹失败：' + str(e))
        # print('source_file', self.source_file)
        try:
            source_data = pd.read_excel(self.source_file)
        except Exception as e:
            # print('错误e：', e)
            self.append_log('---Error pd.read_excel读取文件失败：' + str(e.__traceback__.tb_lineno)  + str(e))
            try:
                source_data = pd.read_csv(self.source_file, encoding='gbk')
            except Exception as e1:
                # print('gbk csv 错误e1：', e1)
                self.append_log('---Error pd.read_csv gbk读取文件失败：' + str(e.__traceback__.tb_lineno)  + str(e1))
                try:
                    source_data = pd.read_csv(self.source_file, encoding='utf-8')
                except Exception as e2:
                    # print('utf8 csv 错误e2：', e2)
                    self.append_log('---Error pd.read_csv utf-8读取文件失败：' + str(e2.__traceback__.tb_lineno)  + str(e2))
                    try:
                        source_data = pd.read_csv(self.source_file, encoding='mbcs')
                    except Exception as e3:
                        # print('mbcs 错误：', e3) 
                        self.append_log('---Error pd.read_csv mbcs读取文件失败：' + str(e3.__traceback__.tb_lineno)  + str(e3))
        # print('----source_data: ', source_data.head(1))
        # self.text_zd
        # print('----text_zd: ', self.text_zd)
        cat_list = source_data.drop_duplicates(subset=[self.text_zd], inplace=False)[self.text_zd].tolist()
        # print('----cat_list: ', cat_list)
        self.append_log('---Tip 拆分字段结果：' + str(cat_list))
        for cat in cat_list:
            temp_data = source_data[source_data[self.text_zd] == cat]
            self.append_log('---Tip 拆分过程，' + str(cat) + ': 数据长度：' + str(len(temp_data)))
            res_path = os.path.join(self.source_path, 'split_res', str(cat) + '-' + str(len(temp_data)) + '.csv.gz')
            temp_data.to_csv(res_path, index=False, compression='gzip')
            if self.flag_mail:
                self.mail_send(cat, res_path)

    # 邮件正文
    def content_change(self):
        self.mail_content = self.content_text.toPlainText()

    def mail_send(self, cate, path):
        try:
            self.append_log('---Tip 开始发送邮件：' + str(cate) + '：' + str(path))
            to_dic = {}
            cc_dic = {}
            to_dic = self.mail_list(self.to_file, cate)
            try:
                cc_dic = self.mail_list(self.cc_file, cate)
            except:
                pass
            try:
                comon_dic = self.mail_list(self.common_file, 'common')
                cc_dic.update(comon_dic)
            except:
                pass
            path_list = []
            path_list.append(path)
            path_list = path_list + self.attach_list
            self.append_log('---Tip 收件、抄送人、附件：' + str(to_dic) + '-' + str(cc_dic) + '-' + str(path_list))
            self.append_log('---Tip 邮件账密：' + str(self.mail_addr) + '-' + str(self.mail_pwd)[:4] + '****' + '-' + str(self.mail_host))
            yag_server = yagmail.SMTP(user=self.mail_addr, password=self.mail_pwd, host=self.mail_host)
            yag_server.send(to=to_dic, cc=cc_dic, subject=self.mail_title, contents=self.mail_content + '<br><br><br>From Robot by zhyoung', attachments=path_list)
            self.append_log('######Tip 发送邮件成功-' + str(cate))
        except Exception as e:
            self.append_log('---Error 发送邮件失败：' + str(e.__traceback__.tb_lineno) + str(e))
        except smtplib.SMTPAuthenticationError as e:
            self.append_log('---Error 发送邮件失败，请检查邮箱及密码：' + str(e.__traceback__.tb_lineno) + str(e)) 
        except smtplib.SMTPServerDisconnected as e:
            self.append_log('---Error 发送邮件失败，SMTP未连接，请先连接：' + str(e.__traceback__.tb_lineno) + str(e)) 

    # 获取收件邮箱地址字典
    def mail_list(self, list_file, cate):
        list_dic = {}
        list_data = pd.read_excel(list_file)
        if cate != 'common':
            list_data = list_data[list_data['CATE'] == cate]
            for i in range(len(list_data)):
                list_dic.setdefault(list_data.iloc[i]['EMAIL_ADDR'], list_data.iloc[i]['EMAIL_NAME'])
            del list_data
            return list_dic
        else:
            for i in range(len(list_data)):
                list_dic.setdefault(list_data.iloc[i]['EMAIL_ADDR'], list_data.iloc[i]['EMAIL_NAME'])
            del list_data
            return list_dic


    # ESC退出
    def keyPressEvent(self, event):
        if event.key() == Qt.Key_Escape:
            self.close()



if __name__ == '__main__':
    app = QApplication(sys.argv)
    window = MyWindow()
    window.show()
    sys.exit(app.exec())